package com.changer.common.component;

import com.changer.common.service.CacheService;
import com.changer.common.vo.ChangerToken;
import com.changer.common.vo.Constants;
import com.changer.common.vo.JsonResponse;
import com.changer.common.vo.enums.ResponseStatus;
import com.changer.framework.util.GoogleJsonUtils;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by pangk on 2016/5/10.
 */
public abstract class TokenAuthInterceptor extends HandlerInterceptorAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(TokenAuthInterceptor.class);

    protected List<String> excludedUrls;

    public void setExcludedUrls(List<String> excludedUrls) {
        this.excludedUrls = excludedUrls;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            if (excludedURI(request)){
                return true;
            }
            String userId = request.getHeader(Constants.USER_KEY);
            String accessUID = request.getParameter(Constants.REQUEST_PARAM_UID);
            if (userId == null){
                userId = request.getParameter(Constants.REQUEST_PARAM_UID);
            }else if(accessUID != null && !userId.equals(accessUID)){
                responseOutWithJson(response,new JsonResponse(ResponseStatus.BAD_ACCESS));
                return false;
            }
            String token = request.getHeader(Constants.TOKEN_KEY);
            CacheService cacheService = getCacheService(request);
            String jsonToken = (String) cacheService.get(Constants.REDIS_PREFIX_TOKEN+":"+token);
            ChangerToken currentToken = GoogleJsonUtils.toBean(jsonToken,ChangerToken.class);
            if(token == null || currentToken == null || !TokenManager.validateToken(request,userId,currentToken)){//非法访问返回
                responseOutWithJson(response,new JsonResponse(ResponseStatus.INVALID_TOKEN));
                return false;
            }else {
                //更新token
                currentToken.setLastUsingTime(System.currentTimeMillis());
                cacheService.put(Constants.REDIS_PREFIX_TOKEN+":"+currentToken.getId(),currentToken,new Date(currentToken.getLastUsingTime()+Constants.REDIS_TIME_OUT_TOKEN));
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            responseOutWithJson(response,new JsonResponse(ResponseStatus.INTER_ERR));
            return false;
        }
        return true;
    }

    /**
     * 以JSON格式输出
     * @param response
     */
    protected void responseOutWithJson(HttpServletResponse response,Object responseObject) {
        //将实体对象转换为JSON Object转换
        JSONObject responseJSONObject = JSONObject.fromObject(responseObject);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        try {
            out = response.getWriter();
            out.append(responseJSONObject.toString());
        } catch (IOException e) {
            LOGGER.error("token interceptor response error",e);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

    protected boolean excludedURI(HttpServletRequest request){
        boolean excluded = false;
        if (excludedUrls != null){
            String uri = request.getRequestURI();
            for (String excludePattern : excludedUrls){
                Pattern r = Pattern.compile(excludePattern);
                Matcher m = r.matcher(uri);
                if (m.find()) {
                    excluded = true;
                    break;
                }
            }
        }
       return excluded;
    }

    protected abstract CacheService getCacheService(HttpServletRequest request);

}
